package com.wms.common.web.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.StringTokenizer;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.wms.common.model.SessionUserInfo;


/**
 * Identify filter that used to validate the request url is accessible or not. 
 * You can configure it through edit the web.xml file.
 * @author fkong
 *
 */
public class IdentifyFilter implements Filter {
	
	/** An instance of FilterConfig. */
	private FilterConfig filterConfig = null;
	
	/** An instance of sprint WebApplicationContext. */
	private static WebApplicationContext appContext;
	
	/** An logger instance. */
	private final Logger logger = Logger.getLogger(IdentifyFilter.class);

	/** The parameter name of login page. */
	private static final String LOGIN_PARAM_PAGE_KEY = "loginPage";
	
	/** The parameter name of excludes list. */
	private static final String EXCLUDES_PARAM_KEY = "excludes";
	
	/** The parameter key of username. */
	private static final String REQUEST_USERNAME_KEY = "encodeUserName";
	
	/** The parameter key of token. */
	private static final String REQUEST_TOKEN_KEY = "token";
	
	/** The login page url. */
	private String loginPage = null;
	
	/** The excludes url list. */
	private final List<String> excludes;
	
	/**
	 * Constructor.
	 */
	public IdentifyFilter() {
		this.excludes = new ArrayList<String>();
	}

	public void init(FilterConfig filterConfig) throws ServletException {
		this.filterConfig = filterConfig;
		
		// Get excludes list, split by comma
		String sExcludes = filterConfig.getInitParameter(EXCLUDES_PARAM_KEY);
		if (sExcludes != null && sExcludes.length() > 0) {
			StringTokenizer st = new StringTokenizer(sExcludes, ", \n\t");
			while (st.hasMoreTokens()) {
				excludes.add(st.nextToken().trim());
			}
		}
		this.loginPage = filterConfig.getInitParameter(LOGIN_PARAM_PAGE_KEY);
		if (this.loginPage == null || this.loginPage.length() == 0) {
			throw new ServletException("The loginPage parameter cannot be null!");
		}
		
		logger.debug("login page:" + loginPage);
		logger.debug("excludes list:" + excludes);
		
		appContext = WebApplicationContextUtils
				.getWebApplicationContext(filterConfig.getServletContext());
	}

	@SuppressWarnings("unchecked")
	public void doFilter(ServletRequest req, ServletResponse res,
			FilterChain chain) throws IOException, ServletException {
		
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
		HttpSession session = request.getSession();
		
		// Get current access url.
		String url = getCurrentUrl(request);
		
		if (!this.excludes.contains(url)) {
//			Object obj = appContext.getBean("sessionUserInfo");
			//clean cache
			HttpServletResponse httpResponse = (HttpServletResponse) res;
			httpResponse.setHeader("Cache-Control","no-cache");
			httpResponse.setHeader("Cache-Control","no-store");
			httpResponse.setDateHeader("Expires", 0);
			httpResponse.setHeader("Pragma","no-cache"); 
			
			Object obj = session.getAttribute("SessionUserInfo");
			SessionUserInfo sessionUserInfo = (SessionUserInfo)obj;
			if (null==sessionUserInfo || null==sessionUserInfo.getUsername()) {
				response.setStatus(500);
				response.sendRedirect(request.getContextPath() + loginPage + "?timeout=1");
				return;
			} 
		} 
		chain.doFilter(req, res);
	}

	public void destroy() {
		this.filterConfig = null;
	}
	
	private String getCurrentUrl(HttpServletRequest request) {
		String uri = request.getRequestURI();
		String contextpath = request.getContextPath();
		String curUrl = uri.substring(uri.indexOf(contextpath)
				+ contextpath.length());
		return curUrl;
	}
	
}

